/**
 * Copyright (c) 2016-2023, Michael Yang 杨福海 (fuhai999@gmail.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.jpress.web.interceptor;

import com.jfinal.aop.Inject;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.LogKit;
import io.jboot.utils.CookieUtil;
import io.jboot.utils.RequestUtil;
import io.jboot.utils.StrUtil;
import io.jboot.web.controller.JbootController;
import io.jboot.web.controller.JbootControllerContext;
import io.jpress.JPressConsts;
import io.jpress.commons.ip2region.Ip2RegionUtil;
import io.jpress.commons.ip2region.IpInfo;
import io.jpress.model.Utm;
import io.jpress.permission.annotation.PermissionDef;
import io.jpress.service.UtmService;
import io.jpress.web.base.ApiControllerBase;


/**
 * @author Michael Yang 杨福海 （fuhai999@gmail.com）
 * @version V1.0
 * @Title: utm拦截器
 */
public class UTMInterceptor implements Interceptor {

    @Inject
    private UtmService utmService;

    public static Utm getCurrentUtm() {
        return JbootControllerContext.get().getAttr(JPressConsts.ATTR_LOGINED_UTM);
    }


    @Override
    public void intercept(Invocation inv) {
        Utm currentUtm = null;
        try {
            if (!RequestUtil.isMultipartRequest(inv.getController().getRequest())) {
                currentUtm = createBaseUtm(inv);
                inv.getController().setAttr(JPressConsts.ATTR_LOGINED_UTM, currentUtm);
            }
        } finally {
            inv.invoke();
        }


        try {
            if (currentUtm != null) {
                utmService.doRecord(currentUtm);
            }
        } catch (Exception ex) {
            LogKit.error(ex.toString());
        }
    }

    private Utm createBaseUtm(Invocation inv) {
        Controller controller = inv.getController();

        Utm utm = new Utm();

        utm.setId(StrUtil.uuid());
        utm.setActionKey(controller.getRequest().getRequestURI());
        utm.setActionQuery(controller.getRequest().getQueryString());
        utm.setActionName(getActionName(inv));
        utm.setAgent(RequestUtil.getUserAgent(controller.getRequest()));
        utm.setReferer(RequestUtil.getReferer(controller.getRequest()));

        String ipAddress = RequestUtil.getIpAddress(controller.getRequest());
        if (StrUtil.isBlank(ipAddress)) {
            ipAddress = "127.0.0.1";
        }
        utm.setIp(ipAddress);

        IpInfo ipInfo = Ip2RegionUtil.memorySearch(ipAddress);
        if (ipInfo != null) {
            utm.setIpRegionCountry(StrUtil.obtainDefault(ipInfo.getCountry(), ""));
            utm.setIpRegionProvince(StrUtil.obtainDefault(ipInfo.getProvince(), ""));
            utm.setIpRegionCity(StrUtil.obtainDefault(ipInfo.getCity(), ""));
        } else {
            utm.setIpRegionCountry("");
            utm.setIpRegionProvince("");
            utm.setIpRegionCity("");
        }

        String uid = CookieUtil.get(controller, JPressConsts.COOKIE_UID);
        if (StrUtil.isNotBlank(uid)) {
            utm.setUserId(Long.valueOf(uid));
            utm.setAnonym(HashKit.md5(uid));
        }

        /**
         * 可能是API的用户，API 通过 jwt 获取用户信息
         */
        else {
            Long userId = getUserIdInJwt(controller);
            if (userId != null) {
                utm.setUserId(userId);
                utm.setAnonym(HashKit.md5(userId.toString()));
            }
            /**
             * 当用户未登录的情况下，创建匿名记录
             */
            else {
                //anonym
                String anonym = CookieUtil.get(controller, JPressConsts.COOKIE_ANONYM);
                if (StrUtil.isNotBlank(anonym)) {
                    utm.setAnonym(anonym);
                } else {
                    anonym = StrUtil.uuid();
                    utm.setAnonym(anonym);
                    CookieUtil.put(controller, JPressConsts.COOKIE_ANONYM, anonym, 60 * 60 * 24 * 365);
                }
            }
        }

        utm.setDataId(0L);
        utm.setDataType(0);

        utm.setSource(controller.getPara("source"));
        utm.setMedium(controller.getPara("medium"));
        utm.setCampaign(controller.getPara("campaign"));
        utm.setContent(controller.getPara("content"));
        utm.setTerm(controller.getPara("term"));

        return utm;
    }


    private static Long getUserIdInJwt(Controller controller) {
        if (controller instanceof ApiControllerBase) {
            Number userId = ((ApiControllerBase) controller).getJwtPara(JPressConsts.JWT_USERID, false);
            if (userId != null) {
                return userId.longValue();
            }
        } else if (controller instanceof JbootController) {
            Number userId = ((JbootController) controller).getJwtPara(JPressConsts.JWT_USERID);
            if (userId != null) {
                return userId.longValue();
            }
        }
        return null;
    }


    private static String getActionName(Invocation inv) {
        PermissionDef permissionDef = inv.getMethod().getAnnotation(PermissionDef.class);
        if (permissionDef != null) {
            return permissionDef.title();
        }

        if (inv.getActionKey().startsWith("/admin")) {
            return "后台操作";
        }

        if ("/".equals(inv.getActionKey())) {
            return "访问首页";
        }

        if (inv.getActionKey().startsWith("/article/category")) {
            return "访问文章分类";
        }

        if (inv.getActionKey().startsWith("/article/")) {
            return "访问文章详情";
        }

        if (inv.getActionKey().startsWith("/product/category")) {
            return "访问产品分类";
        }

        if (inv.getActionKey().startsWith("/product/")) {
            return "访问产品详情";
        }

        return "-";
    }
}
